<?php
/**
 *
 * @author sixihaoyue <sixihaoyue@qq.com>
 */
class UserModel extends BpfModel
{
  public function checkLogin()
  {
    return !empty($_SESSION['user_id']) ? $_SESSION['user_id'] : false;
  }

  /* 生成密码 */
  public function saltPassword($password)
  {
    return md5($password);
  }

  /* 身份验证，成功则返回用户对象 */
  public function auth($username, $password)
  {
    $mysqlModel = $this->getModel('mysql');
    $user_id = $mysqlModel->getSqlBuilder()
      ->select('user_id')->from('users')
      ->where('users.username', $username)
      ->where('password', $this->saltPassword($password))
      ->where('status', User::IS_EFFECTIVE)
      ->query()->field();
    if (!$user_id) {
      return false;
    }
    return $this->getUser($user_id);
  }

  public function createUser($from)
  {
    return User::create($from);
  }

  /* 获取用户对象 */
  public function getUser($user_id, $type = 'user_id')
  {
    static $list = [];
    $cacheid = $user_id . $type;
    if (empty($list[$cacheid])) {
      $mysqlModel = $this->getModel('mysql');
      $User = $mysqlModel->getSqlBuilder()
        ->from('users')
        ->where($type, $user_id)
        ->query()->row('User');
      $list[$cacheid] = $User;
    }
    return $list[$cacheid];
  }

  private function _setusersFilter($query, $filter)
  {
    $query->join('roles', 'roles.role_id = users.role_id', 'LEFT');
    if (isset($filter)) {
      if (!empty($filter['search'])) {
        $search = '%' . $filter['search'] . '%';
        $query->WhereGroupStart();
        $query->Where('users.username LIKE', $search);
        $query->orWhere('users.nickname LIKE', $search);
        $query->whereGroupEnd();
      }
      if (isset($filter['status']) && is_numeric($filter['status'])) {
        if (in_array($filter['status'], [User::IS_EFFECTIVE, User::IS_FORBIDDEN])) {
          $query->Where('users.status', $filter['status']);
        }
      }
      if (isset($filter['role'])) {
        $query->where('users.role_id', $filter['role']);
      }
    }
  }

  public function getusersCount($filter = null)
  {
    $mysqlModel = $this->getModel('mysql');
    $query = $mysqlModel->getSqlBuilder()
        ->select('COUNT(0)')
        ->from('users');
    $this->_setusersFilter($query, $filter);
    return $query->query()->field();
  }

  public function getusersList($filter = null, $page = 1, $rows = 10)
  {
    $mysqlModel = $this->getModel('mysql');
    $query = $mysqlModel->getSqlBuilder()
        ->select('users.*, roles.rolename')
        ->from('users')
        ->limitPage($rows, $page);
    $this->_setusersFilter($query, $filter);
    $query->orderby('users.last_login_time desc');
    return $query->query()->all('User');
  }

  public function batchUpdateUsersStatus($user_ids, $status)
  {
    return $this->getModel('mysql')->getSqlBuilder()->update('users', [
      'updated' => REQUEST_TIME,
      'status' => $status === User::IS_EFFECTIVE ?
        User::IS_EFFECTIVE : User::IS_FORBIDDEN
    ], ['user_id IN' => $user_ids, 'is_supper' => 0])->query()->affectedRows();
  }

  public function createRole($from)
  {
    return Role::create($from);
  }

    /* 获取角色对象 */
  public function getRole($roleid)
  {
    static $list = [];
    if (!isset($list[$roleid])) {
      $mysqlModel = $this->getModel('mysql');
      $User = $mysqlModel->getSqlBuilder()
        ->from('roles')
        ->where('role_id', $roleid)
        ->query()->row('Role');
      $list[$roleid] = $User;
    }
    return $list[$roleid];
  }

  private function _setRolesFilter($query, $filter)
  {
    if (isset($filter)) {
      if (!empty($filter['search'])) {
        $search = '%' . $filter['search'] . '%';
        $query->WhereGroupStart();
        $query->Where('rolename LIKE', $search);
        $query->orWhere('rolename LIKE', $search);
        $query->whereGroupEnd();
      }
      if (isset($filter['status']) && is_numeric($filter['status'])) {
        if (in_array($filter['status'], [Role::IS_EFFECTIVE, Role::IS_FORBIDDEN])) {
          $query->Where('status', $filter['status']);
        }
      }
    }
  }

  public function getRolesList($filter = null, $page = 1, $rows = 10)
  {
    $mysqlModel = $this->getModel('mysql');
    $query = $mysqlModel->getSqlBuilder()
        ->from('roles')
        ->limitPage($rows, $page);
    $this->_setRolesFilter($query, $filter);
    $query->orderby('updated desc');
    return $query->query()->all();
  }

  public function getRolesCount($filter = null)
  {
    $mysqlModel = $this->getModel('mysql');
    $query = $mysqlModel->getSqlBuilder()
        ->select('COUNT(0)')
        ->from('roles');
    $this->_setRolesFilter($query, $filter);
    return $query->query()->field();
  }

  public function batchUpdateRolesStatus($roleids, $status)
  {
    return $this->getModel('mysql')->getSqlBuilder()->update('roles', [
      'updated' => REQUEST_TIME,
      'status' => $status == Role::IS_EFFECTIVE ?
        Role::IS_EFFECTIVE : Role::IS_FORBIDDEN
    ], ['role_id IN' => $roleids])->query()->affectedRows();
  }

  /**
   * 获取权限列表
   * return array
   */
  public function getPermissions()
  {
    $permissions = [];
    foreach ($this->getModel('mysql')->getSqlBuilder()->from('permissions')
      ->query()->all() as $permission) {
        $_permission = $permissions[$permission->name] ?? [];
        $_permission[] = $permission;
        $permissions[$permission->name] = $_permission;
    }
    return $permissions;
  }

}

/* 用户对象类 */
class User extends BpfObject
{
  const IS_EFFECTIVE = 1;
  const IS_FORBIDDEN = 0;

  public static function create($form)
  {
    $UserModel = BpfObject::getModel('User');
    $user_id = BpfObject::getModel('mysql')->getSqlBuilder()->insert('users', [
      'username' => trim($form['username']),
      'password' => $UserModel->saltPassword(trim($form['password'])),
      'nickname' => trim($form['nickname']),
      'avatar' => trim($form['avatar']),
      'nickname' => trim($form['nickname']),
      'role_id' => intval($form['role_id']),
      'status' => intval($form['status']),
      'created' => REQUEST_TIME,
      'updated' => REQUEST_TIME
    ], true)->query()->insertId();
    return $UserModel->getUser($user_id);
  }

  public function setPassword($password)
  {
    $this->password = $this->getModel('User')->saltPassword($password);
  }

  public function getId()
  {
    return $this->user_id;
  }

  public function login()
  {
    $mysqlModel = $this->getModel('mysql');
    $result = $mysqlModel->getSqlBuilder()->update('users', [
       'login_count' => $this->login_count + 1,
       'last_login_time' => REQUEST_TIME
    ], ['user_id' => $this->user_id])->query();
    if ($result->affectedRows()) {
      // 设置 SESSION
      $_SESSION['user_id'] = $this->user_id;
      return true;
    }
    return false;
  }

  public function isSuper()
  {
   return !!$this->is_supper;
  }

  public function checkPermission($rights = [], $type = 'and')
  {
    if ($this->isSuper()) { return true; }
    $role = $this->getRole();
    if ($role->status == Role::IS_FORBIDDEN) { return false; }
    $default = $type === 'and' ? true: false;
    foreach ($rights as $right) {
      $hasPermission = $role->checkPermission($right);
      if ($type === 'and' && !$hasPermission ) {
        return false;
      } else if ($type === 'or' && $hasPermission)  {
        return true;
      }
    }
    return $default;
  }

  public function getRole()
  {
    static $role = null;
    if (!$role) {
      $role = $this->getModel('User')->getRole($this->role_id);
    }
    return $role;
  }

  public function update()
  {
    return $this->getModel('mysql')->getSqlBuilder()->update('users', [
      'password' => trim($this->password),
      'nickname' => trim($this->nickname),
      'avatar' => trim($this->avatar),
      'role_id' => intval($this->role_id),
      'status' => intval($this->status),
      'updated' => REQUEST_TIME
    ], ['user_id' => $this->user_id])->query()->affectedRows();
  }

}

class Role extends BpfObject
{
  const IS_EFFECTIVE = 1;
  const IS_FORBIDDEN = 0;

  public static function create($form)
  {
    $roleid = BpfObject::getModel('mysql')->getSqlBuilder()->insert('roles', [
      'rolename' => trim($form['rolename']),
      'status' => intval($form['status']),
      'created' => REQUEST_TIME,
      'updated' => REQUEST_TIME
    ])->query()->insertId();
    return BpfObject::getModel('User')->getRole($roleid);
  }


  public function getId()
  {
    return $this->role_id;
  }

  public function update()
  {
    return $this->getModel('mysql')->getSqlBuilder()->update('roles', [
      'rolename' => trim($this->rolename),
      'status' => $this->status,
      'updated' => REQUEST_TIME,
    ], ['role_id' => $this->role_id])->query()->affectedRows();
  }

  public function checkPermission($key = null)
  {
    static $permissions = null;
    if (empty($permissions)) {
      $permissions = $this->getModel('mysql')
        ->getSqlBuilder()
        ->from('roles_permissions roles')
        ->join('permissions', 'roles.permission = permissions.permission')
        ->where('roles.role_id', $this->role_id)
        ->query()->allWithKey('permission');
    }
    if ($key) {
      return isset($permissions[$key]);
    }
    return $permissions;
  }

  public function setPermissions($permissions)
  {
    $replaces = [];
    $id = $this->getId();
    foreach ($permissions as $permission) {
      $replaces[] = [
        'role_id' => $id,
        'permission' => $permission,
        'created' => REQUEST_TIME
      ];
    }
    $mysqlModel = $this->getModel('mysql');
    $mysqlModel->getSqlBuilder()->delete('roles_permissions', ['role_id' => $id])->query();
    return $mysqlModel->getSqlBuilder()
      ->replace('roles_permissions', $replaces)->query()->affectedRows();
  }

}
